from turtle import left
from manim import *
from pathlib import Path
import os

FLAGS = f"-pqh"
SCENE = "Main"

template = TexTemplate()
template.add_to_preamble(r"\usepackage{ctex}")
Tex.set_default(tex_template = template, font_size = 28)
MathTex.set_default(font_size = 32)
Text.set_default(font_size = 26)

class Main(MovingCameraScene):
    def construct(self):
        self.add_sound("angel-piano-main-9625.mp3")

        COLOR_A = GREEN_D
        COLOR_B = TEAL_D 
        REMIND_COLOR = RED



        # begin 
        begin = Tex("$\sin x$导数", font_size = 50)
        begin_box = RoundedRectangle(stroke_width=4, stroke_color=WHITE, fill_color=BLUE_B, width=4.5, height=2)
        begin.move_to(begin_box.get_center())

        self.play(GrowFromEdge(begin_box, UL))
        self.play(Write(begin))
        self.play(Unwrite(begin), Uncreate(begin_box))
        self.wait()


        # Part 1.1 SinGraph
        ax = (
            Axes(
            x_range=[-0.2, 6.2, 1],
            y_range=[-1.2, 1.2, 1],
            x_length=6.4,
            y_length=2.4,
            x_axis_config={"numbers_to_include": np.arange(0, 6, 1)},
            y_axis_config={"numbers_to_include": np.arange(-1, 1, 1)},
            tips=False,
            )            
            .add_coordinates()
        )
        ax_label = ax.get_axis_labels(
            x_label=Tex("x"), y_label=Tex("y")
        )

        xVal = ValueTracker(0.8)
        delta_x = ValueTracker(0.4)

        # func = sinx
        def func(x):
            return np.sin(x)
        sin_graph = ax.plot(func, color=MAROON)

        sin_label = ax.get_graph_label(
            sin_graph, "\\sin(x)", x_val=-0.5, direction=UP*6 + LEFT, color=MAROON
        )


        initial_pointA = [ax.coords_to_point(xVal.get_value(), func(xVal.get_value()))]
        dotA = Dot(point=initial_pointA, radius=0.05)
        dotA.set_color(COLOR_A)

        dotA.add_updater(lambda x: x.move_to(ax.c2p(xVal.get_value(), func(xVal.get_value()))))

        initial_pointB = [ax.coords_to_point(xVal.get_value() + delta_x.get_value(), func(xVal.get_value() + delta_x.get_value()))]
        dotB = Dot(point = initial_pointB, radius=0.05)
        dotB.set_color(COLOR_B)

        dotB.add_updater(lambda x: x.move_to(ax.c2p(xVal.get_value() + delta_x.get_value(), func(xVal.get_value() + delta_x.get_value()))))

        labelA = MathTex(*r"(  x  ,   {\sin x}  )".split('  '), font_size=36)
        labelA[1].set_color(COLOR_A)
        labelA[3].set_color(COLOR_A)

        labelA.next_to(dotA, LEFT*2 + DOWN*0.8, buff=0.2)
        def labelAUpdater(obj):
            obj.next_to(dotA, LEFT*2 + DOWN*0.8, buff=0.2)

        labelA.add_updater(labelAUpdater)

        labelB = MathTex(*r"(  {x+\Delta x}  ,   {\sin (x+\Delta x)}  )".split('  '), font_size=36)
        labelB[1].set_color(COLOR_B)
        labelB[3].set_color(COLOR_B)
        labelB.next_to(dotB, RIGHT+UP, buff=0.2)
        def labelBUpdater(obj):
            obj.next_to(dotB, RIGHT+UP, buff=0.2)
        labelB.add_updater(labelBUpdater)

        # line
        linesA = always_redraw(lambda : ax.get_lines_to_point(dotA.get_center()))
        linesB = always_redraw(lambda : ax.get_lines_to_point(dotB.get_center()))


        # area
        area = ax.get_area(sin_graph, x_range=[xVal.get_value(), xVal.get_value() + delta_x.get_value()], color=GRAY_C)
        area.add_updater(lambda x: x.become(ax.get_area(sin_graph, x_range=[xVal.get_value(), xVal.get_value() + delta_x.get_value()], color=GRAY_C)))


        stuff = VGroup(
            ax, area, sin_graph, labelA, labelB, ax_label, sin_label, dotA, dotB, linesA, linesB
        )


        # Part 1.2 SinProof
        left = MathTex(*r"{\Delta y   \over   \Delta x}".split('  ')).shift(UP * 2 + RIGHT*0.6)

        eq1 = MathTex(*r"=  {\sin  (  x  +  {\Delta x}  )  -  {\sin x}  \over  (  x  +  {\Delta x}  )  -  x}".split('  ')).next_to(left, RIGHT)
        
        for i in [8, 16]:
            eq1[i].set_color(COLOR_A)

        for i in [1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 14]:
            eq1[i].set_color(COLOR_B)

        eq1[7].set_color(REMIND_COLOR)
        eq1[15].set_color(REMIND_COLOR)


        eq2 = MathTex(*r"=  {{\sin x}  \cdot  \cos   {\Delta x}  +  \sin   {\Delta x}  \cdot  {\cos x}  -  {\sin x}  \over  {\Delta x}}".split('  ')).move_to(eq1, LEFT).shift(DOWN*1.2)

        eq2[11].set_color(COLOR_A)

        for i in [1, 2, 3, 4, 6, 7, 8, 9, 13]:
            eq2[i].set_color(COLOR_B)

        eq2[5].set_color(REMIND_COLOR)
        eq2[10].set_color(REMIND_COLOR)

        
        eq3 = MathTex(*r"=  {{\sin x}  (  \cos   {\Delta x}  -  1  )  +  \sin   {\Delta x}  \cdot  {\cos x}  \over  {\Delta x}}".split('  ')).move_to(eq2, LEFT).shift(DOWN*1.2)

        eq3[6].set_color(COLOR_A)

        for i in [3, 4, 9, 10, 11, 12, 14]:
            eq3[i].set_color(COLOR_B)
        
        eq3[5].set_color(REMIND_COLOR)
        eq3[8].set_color(REMIND_COLOR)
        
        
        eq4 = MathTex(*r"=  {{\sin x}  (  \cos   {\Delta x}  -  1  )  \over  {\Delta x}}  +  {\sin   {\Delta x}   \cdot  {\cos x}  \over  {\Delta x}}".split('  ')).move_to(eq3, LEFT)

        eq4[6].set_color(COLOR_A)

        for i in [1, 3, 4, 11, 12, 13, 14, 9, 16]:
            eq4[i].set_color(COLOR_B)

        eq4[5].set_color(REMIND_COLOR)
        eq4[10].set_color(REMIND_COLOR)


        eq5 = MathTex(*r"=  {{\sin x}  (  1  -  1  )  \over  {\Delta x}}  +  {\sin   {\Delta x}   \cdot  {\cos x}  \over  {\Delta x}}".split('  ')).move_to(eq4, LEFT).shift(DOWN*1.2)

        eq5[5].set_color(COLOR_A)

        for i in [1, 3, 9, 10, 11, 12, 13, 8, 15]:
            eq5[i].set_color(COLOR_B)
        
        eq5[4].set_color(REMIND_COLOR)
        eq5[9].set_color(REMIND_COLOR)


        eq6 = MathTex(*r"=  {{\sin x}  (  1  -  1  )  \over  {\Delta x}}  +  1  \times  {\cos x}  ".split('  ')).move_to(eq5, LEFT)

        eq6[5].set_color(COLOR_A)

        for i in [1, 3, 10, 11, 12, 8]:
            eq6[i].set_color(COLOR_B)

        eq6[4].set_color(REMIND_COLOR)
        eq6[9].set_color(REMIND_COLOR)

        result = MathTex(r"= \cos x").move_to(eq6, LEFT)

        end_text = Text("故结果为：").next_to(result, DOWN*1.8)
        end_formula = MathTex("(\sin x)' = \cos x", font_size=40).next_to(end_text, RIGHT)
        end_box = SurroundingRectangle(end_formula, color=YELLOW)

        help_box = RoundedRectangle(stroke_width=4, stroke_color=GRAY_C, width=4, height=2, fill_color=GRAY_E, fill_opacity=1)
        help_box.shift(DOWN*1.5 + LEFT*3)

        help_text = Text(r"提示：")
        help_text.move_to(help_box, UP).shift(DOWN*0.2)
        help_text.add_updater(lambda x : x.move_to(help_box, UP).shift(DOWN*0.2))

        help1 = MathTex(r"&\sin (a+b) \\ = &\sin a \cos b + \sin b \cos a").next_to(help_text, DOWN)
        help1.add_updater(lambda x : x.next_to(help_text, DOWN))
        
        help2 = MathTex(r"\cos 0 = 1", font_size=32).next_to(help_text, DOWN*2)
        help2.add_updater(lambda x : x.next_to(help_text, DOWN*2))

        help3 = MathTex(r"\lim_{x \to 0} {\sin x \over x} = 1").next_to(help_text, DOWN)
        help3.add_updater(lambda x : x.next_to(help_text, DOWN) )


        # Animation
        # Scene 1.1 SinGraph 
        self.play(FadeIn(ax), FadeIn(ax_label))
        self.play(Create(sin_graph), Write(sin_label))

        self.play(FadeIn(dotA), FadeIn(linesA))
        self.play(Write(labelA))

        self.play(FadeIn(dotB), FadeIn(linesB))
        self.play(Write(labelB), GrowFromCenter(area))

        # Scene 1.2 过渡 从图像到公式
        self.play(stuff.animate.set(width=6).shift(UP*0.9 + LEFT*2.8), run_time=3)
        self.play(Write(left))
        self.play(Write(eq1[0]), Write(eq1[9]))

        self.play(Indicate(Group(labelA[3], labelB[3])), Indicate(left[0]))
        self.play(ReplacementTransform(Group(labelA[3], labelB[3]).copy(), eq1[1:9]))

        self.play(Indicate(Group(labelA[1], labelB[1])), Indicate(left[2]))
        self.play(ReplacementTransform(Group(labelA[1], labelB[1]).copy(), eq1[10:17]))

        # Scene 1.3 sinproof Animation
        self.play(FadeIn(eq2[0]), FadeIn(eq2[12]))
        self.play(GrowFromCenter(help_box))
        self.play(FadeIn(help_text), FadeIn(help1))
        self.play(Indicate(eq1[1:7]))
        self.play(ReplacementTransform(eq1[1:7].copy(), eq2[1:10]))
        self.play(ReplacementTransform(eq1[7:9].copy(), eq2[10:12]))
        self.play(Indicate(eq1[10:17]))
        self.play(ReplacementTransform(eq1[10:17].copy(), eq2[-1]))

        self.play(FadeIn(eq3[0]), FadeIn(eq3[13]))
        self.play(Indicate(eq2[1]), Indicate(eq2[11]))
        self.play(ReplacementTransform(Group(eq2[1:5].copy(), eq2[10:12].copy()), eq3[1:8]))
        self.play(ReplacementTransform(Group(eq2[5:10].copy(), eq2[-1].copy()), Group(eq3[8:13], eq3[-1])))

        self.play(Indicate(eq3[8]))
        self.play(TransformMatchingTex(eq3, eq4))

        self.play(Indicate(stuff))
        self.play(delta_x.animate.set_value(0.05), run_time=4)
        self.play(FadeTransform(help1, help2))
        self.play(Indicate(eq4[3:5]))
        self.play(FadeTransformPieces(eq4.copy(), eq5))

        self.play(FadeTransform(help2, help3))
        self.play(Indicate(eq5[10:12]), Indicate(eq5[14:16]))
        self.play(FadeTransform(eq5, eq6))
        self.wait()
        self.play(TransformMatchingTex(eq6, result))
        self.wait()

        self.play(Write(end_text))
        self.play(Write(end_formula))
        self.play(Create(end_box))
        self.wait()

        self.play(
            FadeOut(stuff),
            FadeOut(left, eq1, eq2, eq4, result),
            FadeOut(help3, help_text, help_box),
            FadeOut(end_text, end_formula, end_box),
            run_time = 2
        )













        # Part 2.1
        # begin 
        begin = Tex("$\cos x$导数", font_size = 50)
        begin_box = RoundedRectangle(stroke_width=4, stroke_color=WHITE, fill_color=BLUE_B, width=4.5, height=2)
        begin.move_to(begin_box.get_center())

        self.play(GrowFromEdge(begin_box, UL))
        self.play(Write(begin))
        self.play(Unwrite(begin), Uncreate(begin_box))
        self.wait()

        ax = (
            Axes(
            x_range=[-0.2, 6.2, 1],
            y_range=[-1.2, 1.2, 1],
            x_length=6.4,
            y_length=2.4,
            x_axis_config={"numbers_to_include": np.arange(0, 6, 1)},
            y_axis_config={"numbers_to_include": np.arange(-1, 1, 1)},
            tips=False,
            )            
            .add_coordinates()
            # .to_edge(DL, buff=0.25)
        )
        ax_label = ax.get_axis_labels(
            x_label=Tex("x"), y_label=Tex("y")
        )


        xVal.set_value(0.8)
        delta_x.set_value(0.4)

        # func = cosx
        def func(x):
            return np.cos(x)
        cos_graph = ax.plot(func, color=MAROON)

        cos_label = ax.get_graph_label(
            cos_graph, "\\cos(x)", x_val=-0.5, direction=UP + LEFT, color=MAROON
        )


        initial_pointA = [ax.coords_to_point(xVal.get_value(), func(xVal.get_value()))]
        dotA = Dot(point=initial_pointA, radius=0.05)
        dotA.set_color(COLOR_A)

        dotA.add_updater(lambda x: x.move_to(ax.c2p(xVal.get_value(), func(xVal.get_value()))))

        initial_pointB = [ax.coords_to_point(xVal.get_value() + delta_x.get_value(), func(xVal.get_value() + delta_x.get_value()))]
        dotB = Dot(point = initial_pointB, radius=0.05)
        dotB.set_color(COLOR_B)

        dotB.add_updater(lambda x: x.move_to(ax.c2p(xVal.get_value() + delta_x.get_value(), func(xVal.get_value() + delta_x.get_value()))))

        labelA = MathTex(*r"(  x  ,   {\cos x}  )".split('  '), font_size=36)
        labelA[1].set_color(COLOR_A)
        labelA[3].set_color(COLOR_A)
        labelA.next_to(dotA, LEFT*3, buff=0.2)
        def labelAUpdater(obj):
            obj.next_to(dotA, LEFT*3, buff=0.2)
        labelA.add_updater(labelAUpdater)

        labelB = MathTex(*r"(  {x+\Delta x}  ,   {\cos (x+\Delta x)}  )".split('  '), font_size=36)
        labelB[1].set_color(COLOR_B)
        labelB[3].set_color(COLOR_B)
        labelB.next_to(dotB, RIGHT*0.5 + UP*0.5, buff=0.2)
        def labelBUpdater(obj):
            obj.next_to(dotB, RIGHT*0.5 + UP*0.5, buff=0.2)
        labelB.add_updater(labelBUpdater)

        # line
        linesA = always_redraw(lambda : ax.get_lines_to_point(dotA.get_center()))
        linesB = always_redraw(lambda : ax.get_lines_to_point(dotB.get_center()))

        area = ax.get_area(cos_graph, x_range=[xVal.get_value(), xVal.get_value() + delta_x.get_value()], color=GRAY_C)
        area.add_updater(lambda x: x.become(ax.get_area(cos_graph, x_range=[xVal.get_value(), xVal.get_value() + delta_x.get_value()], color=GRAY_C)))

        stuff = VGroup(
            ax, area, cos_graph, labelA, labelB, ax_label, cos_label, dotA, dotB, linesA, linesB
        )


        # Part 2.2 cosProof
        left = MathTex(*r"{\Delta y   \over   \Delta x}".split('  ')).shift(UP * 2 + RIGHT*0.6)

        eq1 = MathTex(*r"=  {\cos  (  x  +  {\Delta x}  )  -  {\cos x}  \over  (  x  +  {\Delta x}  )  -  x}".split('  ')).next_to(left, RIGHT)
        
        for i in [8, 16]:
            eq1[i].set_color(COLOR_A)

        for i in [1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 14]:
            eq1[i].set_color(COLOR_B)

        eq1[7].set_color(REMIND_COLOR)
        eq1[15].set_color(REMIND_COLOR)

        eq2 = MathTex(*r"=  {{\cos x}  \cdot  \cos   {\Delta x}  -  \sin   {\Delta x}  \cdot  {\sin x}  -  {\cos x}  \over  {\Delta x}}".split('  ')).move_to(eq1, LEFT).shift(DOWN*1.2)

        eq2[11].set_color(COLOR_A)

        for i in [1, 2, 3, 4, 6, 7, 8, 9, 13]:
            eq2[i].set_color(COLOR_B)

        eq2[5].set_color(REMIND_COLOR)
        eq2[10].set_color(REMIND_COLOR)

        
        eq3 = MathTex(*r"=  {{\cos x}  (  \cos   {\Delta x}  -  1  )  -  \sin   {\Delta x}  \cdot  {\sin x}  \over  {\Delta x}}".split('  ')).move_to(eq2, LEFT).shift(DOWN*1.2)

        eq3[6].set_color(COLOR_A)

        for i in [3, 4, 9, 10, 11, 12, 14]:
            eq3[i].set_color(COLOR_B)
        
        eq3[5].set_color(REMIND_COLOR)
        eq3[8].set_color(REMIND_COLOR)

        eq4 = MathTex(*r"=  {{\cos x}  (  \cos   {\Delta x}  -  1  )  \over  {\Delta x}}  -  {\sin   {\Delta x}   \cdot  {\sin x}  \over  {\Delta x}}".split('  ')).move_to(eq3, LEFT)

        eq4[6].set_color(COLOR_A)

        for i in [1, 3, 4, 11, 12, 13, 14, 9, 16]:
            eq4[i].set_color(COLOR_B)

        eq4[5].set_color(REMIND_COLOR)
        eq4[10].set_color(REMIND_COLOR)


        # eq5 = MathTex(*r"=  {{\sin x}  (  1  -  1  )  \over  {\Delta x}}  +  {\sin   {\Delta x}   \cdot  {\cos x}  \over  {\Delta x}}".split('  ')).move_to(eq4, LEFT).shift(DOWN*1.2)

        # eq5[5].set_color(COLOR_A)

        # for i in [1, 3, 9, 10, 11, 12, 13, 8, 15]:
            # eq5[i].set_color(COLOR_B)
        
        # eq5[4].set_color(REMIND_COLOR)
        # eq5[9].set_color(REMIND_COLOR)

        # self.add(eq5)

        eq6 = MathTex(*r"=  {{\cos x}  (  {\cos \Delta x}  -  1  )  \over  {\Delta x}}  -  1  \times  {\sin x}  ".split('  ')).move_to(eq4, LEFT).shift(DOWN*1.2)

        eq6[5].set_color(COLOR_A)

        for i in [1, 3, 10, 11, 12, 8]:
            eq6[i].set_color(COLOR_B)

        eq6[4].set_color(REMIND_COLOR)
        eq6[9].set_color(REMIND_COLOR)

        result = MathTex(*r"=  -  \sin x".split('  ')).move_to(eq6, LEFT)
        result[1].set_color(REMIND_COLOR)

        end_text = Text("故结果为：").next_to(result, DOWN*1.8)
        end_formula = MathTex(*r"(\cos x)'  =  -  \sin x".split('  '), font_size=40).next_to(end_text, RIGHT)
        end_formula[2].set_color(REMIND_COLOR)
        end_box = SurroundingRectangle(end_formula, color=YELLOW)

        help_box = RoundedRectangle(stroke_width=4, stroke_color=GRAY_C, width=4, height=2, fill_color=GRAY_E, fill_opacity=1)
        help_box.shift(DOWN*1.5 + LEFT*3)

        help_text = Text(r"提示：")
        help_text.move_to(help_box, UP).shift(DOWN*0.2)
        help_text.add_updater(lambda x : x.move_to(help_box, UP).shift(DOWN*0.2))

        help1 = MathTex(r"&\cos (a+b) \\ = &\cos a \cos b - \sin b \sin a").next_to(help_text, DOWN)
        help1.add_updater(lambda x : x.next_to(help_text, DOWN))
        
        # help2 = MathTex(r"\cos 0 = 1", font_size=32).next_to(help_text, DOWN*2)
        # help2.add_updater(lambda x : x.next_to(help_text, DOWN*2))
        after_text = Text(r"稍后证明：")
        after_text.move_to(help_text)
        after_text.add_updater(lambda x : x.move_to(help_text))

        after = MathTex(r"\lim_{\Delta x \to 0} {\cos \Delta x - 1 \over \Delta x} = 0").next_to(after_text, DOWN)
        after.add_updater(lambda x : x.next_to(after_text, DOWN) )

        help3 = MathTex(r"\lim_{x \to 0} {\sin x \over x} = 1").next_to(help_text, DOWN)
        help3.add_updater(lambda x : x.next_to(help_text, DOWN) )


        # Animation
        # Scene 2.1 CosGraph 
        self.play(FadeIn(ax), FadeIn(ax_label))
        self.play(Create(cos_graph), Write(cos_label))

        self.play(FadeIn(dotA), FadeIn(linesA))
        self.play(Write(labelA))

        self.play(FadeIn(dotB), FadeIn(linesB))
        self.play(Write(labelB), GrowFromCenter(area))

        # Scene 2.2 过渡 从图像到公式
        self.play(stuff.animate.set(width=6).shift(UP*0.9 + LEFT*2.8), run_time=3)
        self.play(Write(left))
        self.play(Write(eq1[0]), Write(eq1[9]))

        self.play(Indicate(Group(labelA[3], labelB[3])), Indicate(left[0]))
        self.play(ReplacementTransform(Group(labelA[3], labelB[3]).copy(), eq1[1:9]))

        self.play(Indicate(Group(labelA[1], labelB[1])), Indicate(left[2]))
        self.play(ReplacementTransform(Group(labelA[1], labelB[1]).copy(), eq1[10:17]))

        # Scene 3.3 cosproof Animation
        self.play(FadeIn(eq2[0]), FadeIn(eq2[12]))
        self.play(GrowFromCenter(help_box))
        self.play(FadeIn(help_text), FadeIn(help1))
        self.play(Indicate(eq1[1:7]))
        self.play(ReplacementTransform(eq1[1:7].copy(), eq2[1:10]))
        self.play(ReplacementTransform(eq1[7:9].copy(), eq2[10:12]))
        self.play(Indicate(eq1[10:17]))
        self.play(ReplacementTransform(eq1[10:17].copy(), eq2[-1]))

        self.play(FadeIn(eq3[0]), FadeIn(eq3[13]))
        self.play(Indicate(eq2[1]), Indicate(eq2[11]))
        self.play(ReplacementTransform(Group(eq2[1:5].copy(), eq2[10:12].copy()), eq3[1:8]))
        self.play(ReplacementTransform(Group(eq2[5:10].copy(), eq2[-1].copy()), Group(eq3[8:13], eq3[-1])))

        self.play(Indicate(eq3[8]))
        self.play(TransformMatchingTex(eq3, eq4))

        self.play(Indicate(stuff))
        self.play(delta_x.animate.set_value(0.05), run_time=4)

        # # self.play(FadeTransform(help1, help2))
        # # self.play(Indicate(eq4[3:5]))
        # # self.play(FadeTransformPieces(eq4.copy(), eq5))

        self.play(FadeTransform(help1, help3))
        self.play(Indicate(eq4[11:13]), Indicate(eq4[15:17]))
        self.play(FadeTransform(eq4.copy(), eq6))
        self.wait()

        self.play(FadeTransform(help_text, after_text))
        self.play(FadeTransform(help3, after))
        self.play(Indicate(eq6[2:9]))
        self.play(ReplacementTransform(eq6, result))
        self.wait()

        self.play(Write(end_text))
        self.play(Write(end_formula))
        self.play(Create(end_box))
        self.wait()

        
        self.play(
            FadeOut(stuff),
            FadeOut(left, eq1, eq2, eq4, eq6, result),
            FadeOut(end_text, end_formula, end_box),
            run_time = 2
        )














        # Part 3.1 Graph
        self.camera.frame.save_state()
        # Part 3.1 Graph
        ax = (
            Axes(
            x_range=[-0.2, 6.2, 1],
            y_range=[-1.2, 1.2, 1],
            x_length=6.4,
            y_length=2.4,
            x_axis_config={"numbers_to_include": np.arange(0, 6, 1)},
            y_axis_config={"numbers_to_include": np.arange(-1, 1, 1)},
            tips=False,
            )            
        )
        ax.shift(UP + LEFT*2)

        xVal.set_value(0)
        delta_x.set_value(0.4)

        # func = cosx
        def func(x):
            return np.cos(x)
        cos_graph = ax.plot(func, color=MAROON)

        cos_label = ax.get_graph_label(
            cos_graph, "\\cos(x)", x_val=-0.5, direction=UP*2 + LEFT, color=MAROON
        )

        initial_pointA = [ax.coords_to_point(xVal.get_value(), func(xVal.get_value()))]
        dotA = Dot(point=initial_pointA, radius=0.05)
        dotA.set_color(COLOR_A)

        dotA.add_updater(lambda x: x.move_to(ax.c2p(xVal.get_value(), func(xVal.get_value()))))

        initial_pointB = [ax.coords_to_point(xVal.get_value() + delta_x.get_value(), func(xVal.get_value() + delta_x.get_value()))]
        dotB = Dot(point = initial_pointB, radius=0.05)
        dotB.set_color(COLOR_B)

        dotB.add_updater(lambda x: x.move_to(ax.c2p(xVal.get_value() + delta_x.get_value(), func(xVal.get_value() + delta_x.get_value()))))

        label_A0 = MathTex(*r"(  0  ,   {\cos 0}  )".split('  '), font_size=36)
        label_A0[1].set_color(COLOR_A)
        label_A0[3].set_color(COLOR_A)

        label_A0.next_to(dotA, LEFT*2, buff=0.2)
        def label_A0Updater(obj):
            obj.next_to(dotA, LEFT*2, buff=0.2)

        label_A0.add_updater(label_A0Updater)

        label_B0 = MathTex(*r"(  {\Delta x}  ,   {\cos \Delta x}  )".split('  '), font_size=36)
        label_B0[1].set_color(COLOR_B)
        label_B0[3].set_color(COLOR_B)
        label_B0.next_to(dotB, RIGHT*0.5 + UP*0.5, buff=0.2)
        def label_B0Updater(obj):
            obj.next_to(dotB, RIGHT*0.5 + UP*0.5, buff=0.2)
        label_B0.add_updater(label_B0Updater)

        hA = always_redraw(lambda : ax.get_vertical_line(ax.c2p(xVal.get_value(), func(xVal.get_value()))).set_color(COLOR_A))

        hB = always_redraw(lambda : ax.get_vertical_line(
            ax.c2p(xVal.get_value() + delta_x.get_value(), func(xVal.get_value() + delta_x.get_value()))
            ).set_color(COLOR_B))

        hA_label = MathTex(r"h_1", color = COLOR_A).next_to(hA, LEFT)
        hA_label.add_updater(lambda x : x.next_to(hA, LEFT))
        hB_label = MathTex(r"h_2", color = COLOR_B).next_to(hB, RIGHT)
        hB_label.add_updater(lambda x : x.next_to(hB, RIGHT))

        area = ax.get_area(cos_graph, x_range=[xVal.get_value(), xVal.get_value() + delta_x.get_value()], color=GRAY_C)
        area.add_updater(lambda x: x.become(ax.get_area(cos_graph, x_range=[xVal.get_value(), xVal.get_value() + delta_x.get_value()], color=GRAY_C)))


        # Part 3.2  公式
        help_box_new = RoundedRectangle(stroke_width=4, stroke_color=GRAY_C, width=4, height=2, fill_color=GRAY_E, fill_opacity=1)
        help_box_new.shift(UP*1.5 + RIGHT*4)

        proof_text = Text(r"证明：")
        proof_text.move_to(help_box_new, UP).shift(DOWN*0.2)
        proof_text.add_updater(lambda x : x.move_to(help_box_new, UP).shift(DOWN*0.2))

        after_new = MathTex(*r"\lim_{\Delta x \to 0}  {\cos \Delta x - 1 \over \Delta x}  =  0".split('  ')).next_to(proof_text, DOWN)
        after_new.add_updater(lambda x : x.next_to(proof_text, DOWN))


        eq1 = MathTex(*r"{{\cos \Delta x}  \over  {\Delta x}}  -  {1  \over  {\Delta x}}".split('  '))
        eq1.next_to(help_box_new, DOWN*3.5).shift(LEFT*2)

        eq2 = MathTex(*r"=  {h_2  \over  {\Delta x}}  -  {h_1  \over  {\Delta x}}".split('  '))
        eq2[1].set_color(COLOR_B)
        eq2[5].set_color(COLOR_A)
        eq2.next_to(eq1, RIGHT)

        eq3 = MathTex(r"=", r"0")
        eq3.move_to(eq2, LEFT).shift(DOWN)

        end = Text("证明完毕", font_size=34)
        end.next_to(eq3[0], DOWN*2.5)
        end_box = SurroundingRectangle(end, color=YELLOW)

        temp = MathTex(r"\begin{cases} \cos 0 &= h_1  \\ \cos \Delta x &= h_ 2 \end{cases}").shift(DOWN*1.5, LEFT*3)	
        temp[0][1:8].set_color(COLOR_A)
        temp[0][8:16].set_color(COLOR_B)

        temp_text = Tex("$\Delta x$趋近于$0$时，", "$h_1$" , "$=$", "$h_2$").next_to(temp, DOWN)
        temp_text[1].set_color(COLOR_A)
        temp_text[3].set_color(COLOR_B)


        # Animation
        self.play(
            ReplacementTransform(help_box, help_box_new),
            ReplacementTransform(after_text, proof_text),
            TransformMatchingTex(after, after_new),
            run_time=3
        )

        self.play(FadeIn(ax, area, cos_graph, label_A0, label_B0, cos_label, dotA, dotB))

        self.play(ReplacementTransform(after_new[1].copy(), eq1))
        self.play(ReplacementTransform(Group(eq1[1:4], eq1[5:7]).copy(), Group(eq2[0], eq2[2:5], eq2[6:8])))
        self.play(Indicate(label_A0[3]), Indicate(label_B0[3]))
        self.play(
            Create(hA), Create(hB), Write(hA_label), Write(hB_label),
            Write(temp[0][0]),
            Write(temp[0][1:8]),
            Write(temp[0][8:16])
        )
        self.wait()
        self.play(ReplacementTransform(hA_label.copy(), eq2[1]), ReplacementTransform(hB_label.copy(), eq2[5]))

        self.play(self.camera.frame.animate.move_to(ax).set(width=ax.width*1.2))
        self.play(
            delta_x.animate.set_value(0.03),
            run_time = 4
        )
        self.play(Restore(self.camera.frame))
        self.play(FadeIn(temp_text))
        self.play(Indicate(eq2))
        self.play(ReplacementTransform(eq2.copy(), eq3))

        self.play(Write(end))
        self.play(Create(end_box))
        self.wait()





if __name__ == '__main__':
    script_name = f"{Path(__file__).resolve()}"
    os.system(f"manim {FLAGS} {script_name} {SCENE}")